package com.whalehearing.tingyou.common.utils;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.whalehearing.tingyou.common.core.domain.AjaxResult;
import com.whalehearing.tingyou.common.core.domain.R;
import com.whalehearing.tingyou.common.core.redis.RedisCache;
import com.whalehearing.tingyou.common.enums.GaoDeEnum;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.pinyin4j.PinyinHelper;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author: shensh
 * @Desc:
 * @create: 2024-09-06 17:42
 **/

@Component
@Slf4j
public class GaoDeMapUtil {

    /**
     * 功能描述: 高德地图Key
     *
     * @param null
     * @return
     * @author
     * @date 2022-01-26 09:13:40
     */
    private static final String GAO_DE_KEY = "5faf41952ce689dfc0ecf61f7cddbc89";

    private static final String AROUND_CACHE_PREFIX = "gaode:around:";

    private static final String DETAIL_CACHE_PREFIX = "gaode:detail:";

    private static final String LOCATION_CACHE_PREFIX = "gaode:location:";

    private static final String DISTANCE_CACHE_PREFIX = "gaode:distance:";

    private static final String AREA_CACHE_PREFIX = "gaode:area:";
    private static final int CACHE_EXPIRATION_MINUTES = 60;  // 缓存过期时间，单位为分钟

    private static final int CACHE_EXPIRATION_HOURS = 12;  // 缓存过期时间，单位为小时

    private static final int PAGE_SIZE = 50; // 每页最多50条数据
    private static final int MAX_PAGES = 20; // 最多获取20页数据（20 * 50 = 1000条）

    public static final String DEFAULT_STORE_IMAGE= "https://tingyou-jtdymt.oss-cn-shenzhen.aliyuncs.com/tingyou-images/2024/12/18/676294a0ccb656b63f50434b.png";


    @Autowired
    private RedisCache redisCache;

    //申请的账户Key

    /**
     * 功能描述: 根据地址名称得到两个地址间的距离
     *
     * @param start 起始位置
     * @param end   结束位置
     * @return long 两个地址间的距离
     * @author isymikasan
     * @date 2022-01-26 09:16:04
     */
    public Long getDistanceByAddress(String start, String end) {
        String startLonLat = getLonLat(start).toString();
        String endLonLat = getLonLat(end).toString();
        Long distance = Long.valueOf(getDistance(startLonLat, endLonLat).toString());
        return distance;
    }

    /**
     * 功能描述: 地址转换为经纬度
     *
     * @param address 地址
     * @return java.lang.String 经纬度
     * @author isymikasan
     * @date 2022-01-26 09:17:13
     */
    public String getLonLat(String address) {
        String LngAndLat ="";
        try {
            String locationCache = redisCache.getCacheObject("gaode:location:" + address);
            if (locationCache != null) {
                LngAndLat = locationCache;
                return LngAndLat;
            }
            // 返回输入地址address的经纬度信息, 格式是 经度,纬度
            String queryUrl = "http://restapi.amap.com/v3/geocode/geo?key=" + GAO_DE_KEY + "&address=" + address;
            // 高德接口返回的是JSON格式的字符串
            String queryResult = getResponse(queryUrl);
            JSONObject jsonObject = JSONObject.parseObject(queryResult);
            //JSONObject jobJSON = JSONObject.parseObject(jsonObject.get("geocodes").toString().substring(1, jsonObject.get("geocodes").toString().length() - 1));
            String status = jsonObject.get("status").toString();
            if (status.equals("1")) {

                LngAndLat=jsonObject.getJSONArray("geocodes").getJSONObject(0).getString("location");
                redisCache.setCacheObject(LOCATION_CACHE_PREFIX + address,LngAndLat, CACHE_EXPIRATION_MINUTES, TimeUnit.MINUTES);
            }

            //log.info("经纬度为：" + LngAndLat);
        } catch (Exception e) {
           log.error(e.getMessage(),e);
        }
        return LngAndLat;
    }

    /**
     * 将经纬度 转换为 地址
     *
     * @param longitude 经度
     * @param latitude  纬度
     * @return 地址名称
     * @throws Exception
     */
    public String getAddress(String longitude, String latitude) throws Exception {
        String url;
        String address = "";
        try {
            url = "http://restapi.amap.com/v3/geocode/regeo?output=JSON&location=" + longitude + "," + latitude
                    + "&key=" + GAO_DE_KEY + "&radius=0&extensions=base";

            // 高德接口返回的是JSON格式的字符串
            String queryResult = getResponse(url);
            if (ObjectUtils.isNull(queryResult)) {
                return address;
            }

            // 将获取结果转为json 数据
            JSONObject obj = JSONObject.parseObject(queryResult);
            if (obj.get(GaoDeEnum.STATUS.getCode()).toString().equals(GaoDeEnum.INT_ONE.getCode())) {
                // 如果没有返回-1
                JSONObject reGeoCode = obj.getJSONObject(GaoDeEnum.RE_GEO_CODE.getCode());
                if (reGeoCode.size() > 0) {
                    // 在regeocode中拿到 formatted_address 具体位置
                    address = reGeoCode.get("formatted_address").toString();
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        }
        return address;
    }

    /**
     * 功能描述: 根据两个定位点的经纬度算出两点间的距离
     *
     * @param startLonLat 起始经纬度
     * @param endLonLat   结束经纬度（目标经纬度）
     * @return java.lang.Long 两个定位点之间的距离
     * @author isymikasan
     * @date 2022-01-26 09:47:42
     */
    public Double getDistance(String startLonLat, String endLonLat) {
        // 返回起始地startAddr与目的地endAddr之间的距离，单位：米
        Double distance = null;
        try {
            Double distanceCache=redisCache.getCacheObject(DISTANCE_CACHE_PREFIX+ startLonLat+"_" + endLonLat);
            if(distanceCache!=null){
                return distanceCache;
            }
            String queryUrl =
                    "http://restapi.amap.com/v3/distance?key=" + GAO_DE_KEY + "&origins=" + startLonLat
                            + "&destination="+ endLonLat;
            String queryResult = getResponse(queryUrl);
            JSONObject job = JSONObject.parseObject(queryResult);
            JSONArray ja = job.getJSONArray("results");
            JSONObject jobO = JSONObject.parseObject(ja.getString(0));
            Long distance1 = Long.parseLong(jobO.get("distance").toString());
            //由米转为公里
            distance= (double)distance1/1000;
            BigDecimal bd=new BigDecimal(distance).setScale(1, RoundingMode.CEILING);
            distance=bd.doubleValue();
            redisCache.setCacheObject(DISTANCE_CACHE_PREFIX+ startLonLat+"_" + endLonLat,distance,CACHE_EXPIRATION_MINUTES, TimeUnit.MINUTES);
            log.info("两地的距离为：" , distance);
        } catch (Exception e) {
            log.error(e.getMessage(),e.toString());
        }
        return distance;
    }

    public ResultZengJun getAround(String longitude, String latitude) {
        // 搜索关键字
        String keywords = "助听器";
        //搜索半径，周边50公里
        Integer searchRadius=50000;
        // 生成缓存键
        String cacheKey = generateCacheKey(Double.valueOf(latitude), Double.valueOf(longitude), keywords, searchRadius);
        // 从缓存中获取数据
        List<Map<String,Object>> cacheList = redisCache.getCacheList(cacheKey);
        if(CollectionUtils.isNotEmpty(cacheList)){
            return ResultZengJun.success(cacheList,"从redis缓存中获取高德周边助听器门店成功");
        }
        // 构建请求URL
        String url = "https://restapi.amap.com/v3/place/around" + "?location=" + longitude + "," + latitude
                + "&keywords=" + keywords
                + "&radius=" + searchRadius
                + "&key=" + GAO_DE_KEY
                + "&output=json";
        HttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(url);

        try {
            HttpResponse response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            String responseStr = EntityUtils.toString(entity, "UTF-8");
            log.info("高德API返回的门店数据:{}",responseStr);
            JSONObject jsonObject = JSON.parseObject(responseStr);
            boolean flag = jsonObject.containsKey("pois");
            if(!flag){
                return ResultZengJun.error("没有符合条件的数据");
            }
            JSONArray jsonArray = jsonObject.getJSONArray("pois");
            //JSONObject responseJson = new JSONObject(responseStr);
            //JSONArray poisArray = responseJson.getJSONArray("pois");
            List<Map<String,Object>>list = new ArrayList<>();
            for (int i = 0; i < jsonArray.size(); i++) {
                Map<String,Object> map = new HashMap<String, Object>();
                JSONObject poiObject = jsonArray.getJSONObject(i);
                String name = poiObject.getString("name");
                String address = poiObject.getString("address");
                String photos = poiObject.getString("photos");
                String telephone = poiObject.getString("tel");
                String distance = poiObject.getString("distance");
                String location = poiObject.getString("location");
                //根据id调高德detail接口获取门店详情
                String id = poiObject.getString("id");
                JSONArray jsonArray1 = JSON.parseArray(photos);
                String storePhotoUrl ="";
                //先取第1张图
                if(jsonArray1.size()>0){
                    storePhotoUrl =jsonArray1.getJSONObject(0).getString("url");
                }
                map.put("name", name);
                map.put("address", address);
                map.put("telephone", telephone);
                map.put("distance", distance);
                map.put("location", location);
                map.put("photos", storePhotoUrl);
                map.put("id", id);
                list.add(map);
            }
            if(CollectionUtils.isNotEmpty(list)){
                redisCache.setCacheList(cacheKey,list,CACHE_EXPIRATION_HOURS, TimeUnit.HOURS);
            }
            return ResultZengJun.success(list,"获取高德周边助听器门店成功");
        } catch (IOException e) {
           log.error(e.toString(),e.toString());
            return ResultZengJun.error("获取高德周边助听器门店失败,原因是"+e);
        }

    }

    /**
     * 分页获取所有POI数据
     */
    public  ResultZengJun getAroundByLocation(String location) {
        // 搜索关键字
        String keywords = "助听器";
        //搜索半径，周边50公里
        Integer searchRadius=50000;
        // 生成缓存键
        String cacheKey = getCacheKey(location, keywords, searchRadius);
        // 从缓存中获取数据
        List<Map<String,Object>> cacheList = redisCache.getCacheList(cacheKey);
        if(CollectionUtils.isNotEmpty(cacheList)){
            return ResultZengJun.success(cacheList,"从redis缓存中获取高德周边助听器门店成功");
        }
        String BASE_URL = "https://restapi.amap.com/v3/place/around";
        List<JsonNode> allPois = new ArrayList<>();
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            for (int page = 1; page <= MAX_PAGES; page++) {
                // 构造请求URL
                String url = String.format("%s?key=%s&location=%s&radius=%d&keywords=%s&offset=%d&page=%d",
                        BASE_URL,
                        GAO_DE_KEY,
                        location,
                        searchRadius,
                        URLEncoder.encode(keywords, StandardCharsets.UTF_8.toString()),
                        PAGE_SIZE,
                        page);

                // 发送GET请求
                HttpGet request = new HttpGet(url);
                try (CloseableHttpResponse response = httpClient.execute(request)) {
                    HttpEntity entity = response.getEntity();
                    if (entity != null) {
                        String jsonResponse = EntityUtils.toString(entity);
                        ObjectMapper mapper = new ObjectMapper();
                        JsonNode rootNode = mapper.readTree(jsonResponse);

                        // 检查API返回状态
                        String status = rootNode.path("status").asText();
                        if (!"1".equals(status)) {
                            log.error("高德API调用失败: " + rootNode.path("info").asText());
                            break;
                        }

                        // 解析POI数据
                        JsonNode pois = rootNode.path("pois");
                        if (pois.isArray() && pois.size() > 0) {
                            pois.forEach(allPois::add);
                        } else {
                            break; // 没有更多数据，退出循环
                        }
                    }
                }
            }
        } catch (IOException e) {
            log.error("高德API调用失败: " + e.getMessage());
        }
        if(CollectionUtils.isEmpty(allPois)){
            return ResultZengJun.error("没有符合条件的数据");
        }
        List<Map<String,Object>> list = getCoreMapData(allPois);
        redisCache.setCacheList(cacheKey,list,CACHE_EXPIRATION_HOURS, TimeUnit.HOURS);
        return ResultZengJun.success(list,"获取高德周边助听器门店成功");
    }


    /**
     * 解析并打印API响应
     */
    public   List<Map<String,Object>> getCoreMapData(List<JsonNode> pois) {
        List<Map<String,Object>>list = new ArrayList<>();
        Set<String> idSet = new HashSet<>();
        for (JsonNode poi : pois) {
            String id = poi.path("id").asText();
            if (idSet.contains(id)) {
                continue;
            }
            idSet.add(id);
            Map<String,Object> map = new HashMap<>();
            String name = poi.path("name").asText();
            String address = poi.path("address").asText();
            String location = poi.path("location").asText();
            String telephone = poi.path("tel").asText();
            String distance = poi.path("distance").asText();

            //获取返回的 photos 数组
            JsonNode photosNode = poi.path("photos");
//            List<String> photos = new ArrayList<>();
//            if (photosNode.isArray()) {
//                for (JsonNode photo : photosNode) {
//                    String photoUrl = photo.path("url").asText();
//                    photos.add(photoUrl);
//                }
//            }
            String firstPhotoUrl ="";
            if (photosNode.isArray() && photosNode.size() > 0) {
                // 获取第1张照片的URL
                 firstPhotoUrl = photosNode.get(0).path("url").asText();
            }
            map.put("name", name);
            map.put("address", address);
            map.put("telephone", telephone);
            map.put("distance", distance);
            map.put("location", location);
            map.put("photos", StringUtils.isBlank(firstPhotoUrl)?DEFAULT_STORE_IMAGE:firstPhotoUrl);
            map.put("id", id);
            list.add(map);
        }
        return list;
    }

    /* *
     * 根据poi的id获取地址详情
     * @param id id为调around接口返回的poi的id
     * @return com.whalehearing.tingyou.common.utils.ResultZengJun
     * @author shensh
     * @create 2025/2/7
     **/
    public ResultZengJun getDetailByPoiId(String id) {
        String cacheKey = DETAIL_CACHE_PREFIX + id;
        List<Map<String,Object>> cacheList = redisCache.getCacheList(cacheKey);
        if(CollectionUtils.isNotEmpty(cacheList)) {
            return ResultZengJun.success(cacheList, "门店详情获取成功");
        }
        String url = "https://restapi.amap.com/v3/place/detail?id=" + id + "&key=" + GAO_DE_KEY + "&output=json";
        HttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(url);
        try {
            HttpResponse response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            String responseStr = EntityUtils.toString(entity, "UTF-8");
            log.info("高德返回的门店详情数据:{}", responseStr);
            JSONObject jsonObject = JSON.parseObject(responseStr);
            boolean flag = jsonObject.containsKey("pois");
            if (!flag) {
                return ResultZengJun.error("没有符合条件的数据");
            }
            JSONArray jsonArray = jsonObject.getJSONArray("pois");
            List<Map<String,Object>> list = new ArrayList<>();
            for (int i = 0; i < jsonArray.size(); i++) {
                Map<String, Object> map = new HashMap<String, Object>();
                JSONObject poiObject = jsonArray.getJSONObject(i);
                // String type = poiObject.getString("type");
                String name = poiObject.getString("name");
                String address = poiObject.getString("address");
                String photos = poiObject.getString("photos");
                String telephone = poiObject.getString("tel");
                String distance = poiObject.getString("distance");
                String location = poiObject.getString("location");
                JSONArray photoArray = JSON.parseArray(photos);
                List<String> storePhotos = new ArrayList<>();
                if(photoArray.size()>0){
                    for (int j = 0; j < photoArray.size(); j++) {
                        JSONObject jsonObject1 = photoArray.getJSONObject(i);
                        if(jsonObject1.containsKey("url")) {
                            storePhotos.add(jsonObject1.getString("url"));
                        }
                    }
                }
                String storePhotoUrl=CollectionUtils.isEmpty(storePhotos)?"":String.join(",",storePhotos);
                map.put("id", id);
                map.put("name", name);
                map.put("address", address);
                map.put("telephone", telephone);
                map.put("distance", distance);
                map.put("location", location);
                map.put("photos", storePhotoUrl);
                list.add(map);
            }
            redisCache.setCacheList(cacheKey,list,CACHE_EXPIRATION_HOURS, TimeUnit.HOURS);
            return ResultZengJun.success(list,"门店详情获取成功");
        } catch (IOException e) {
            log.error(e.toString(),e);
            return ResultZengJun.error("门店详情获取失败,原因是"+e);
        }

    }

    private static String generateCacheKey(double latitude, double longitude, String keywords, int radius) {
        return AROUND_CACHE_PREFIX + String.format("%.6f_%.6f_%s_%d", longitude, latitude, keywords, radius);
    }

    private static String getCacheKey(String location, String keywords, int radius) {
        return AROUND_CACHE_PREFIX + String.format("%s_%s_%d", location, keywords, radius);
    }

    /**
     * 功能描述: 发送请求
     *
     * @param serverUrl 请求地址
     * @return java.lang.String
     * @author isymikasan
     * @date 2022-01-26 09:15:01
     */
    private static String getResponse(String serverUrl) {
        // 用JAVA发起http请求，并返回json格式的结果
        StringBuffer result = new StringBuffer();
        try {
            URL url = new URL(serverUrl);
            URLConnection conn = url.openConnection();
            BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
            in.close();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result.toString();
    }


    // 调用高德 API 获取省份和城市信息
    private  String getAddressByIP(String ip) {
        String address="";
        String cacheObject = redisCache.getCacheObject(AREA_CACHE_PREFIX + ip);
        if(cacheObject!=null){
            return cacheObject;
        }
        final String AMAP_URL = "https://restapi.amap.com/v3/ip?ip=%s&key=" + GAO_DE_KEY;
        String url = String.format(AMAP_URL, ip);
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpGet request = new HttpGet(url);
            try (CloseableHttpResponse response = httpClient.execute(request)) {
                HttpEntity entity = response.getEntity();
                String jsonResponse = EntityUtils.toString(entity);
                // 解析返回的 JSON 数据（省份和城市）
                if (jsonResponse.contains("\"status\":\"1\"")) {
                    String province = extractJsonValue(jsonResponse, "province");
                    String city = extractJsonValue(jsonResponse, "city");
                    if (province != null && isAllChinese(province)) {
                        address=province;
                    }
                    if (city != null && isAllChinese(city)) {
                        address+=city;
                    }
                    redisCache.setCacheObject(AREA_CACHE_PREFIX+ip,address,CACHE_EXPIRATION_MINUTES, TimeUnit.MINUTES);
                }
            }
        } catch (Exception e) {
           log.error(e.getMessage(),e);
        }
        return address;
    }

    /**
     * 获取中国所有城市
     */
    private static List<String> getChineseCities() {
        List<String> cities = new ArrayList<>();
        String BASE_URL = "https://restapi.amap.com/v3/config/district";
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            // 构造请求URL
            String url = String.format("%s?key=%s&keywords=%s&subdistrict=%d&extensions=base",
                    BASE_URL,
                    GAO_DE_KEY,
                    URLEncoder.encode("中国", StandardCharsets.UTF_8.toString()),
                    3); // subdistrict=2 表示获取城市

            // 发送GET请求
            HttpGet request = new HttpGet(url);
            try (CloseableHttpResponse response = httpClient.execute(request)) {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    String jsonResponse = EntityUtils.toString(entity);
                    ObjectMapper mapper = new ObjectMapper();
                    JsonNode rootNode = mapper.readTree(jsonResponse);

                    // 检查API返回状态
                    String status = rootNode.path("status").asText();
                    if (!"1".equals(status)) {
                        System.out.println("API调用失败: " + rootNode.path("info").asText());
                        return cities;
                    }

                    // 解析城市数据
                    JsonNode districtsNode = rootNode.path("districts").get(0).path("districts");
                    if (districtsNode.isArray()) {
                        for (JsonNode district : districtsNode) {
                            String name = district.path("name").asText();
                            cities.add(name);
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return cities;
    }

    /**
     * 按字母顺序排序城市
     */
    private static void sortCitiesAlphabetically(List<String> cities) {
        Collections.sort(cities, new Comparator<String>() {
            @Override
            public int compare(String city1, String city2) {
                // 将中文城市名称转换为拼音
                String pinyin1 = convertToPinyin(city1);
                String pinyin2 = convertToPinyin(city2);
                return pinyin1.compareTo(pinyin2);
            }
        });
    }

    // 判断字符串是否完全由汉字组成
    public static boolean isAllChinese(String str) {
        // 这个正则表达式匹配的是汉字的 Unicode 范围
        String regex = "^[\\u4e00-\\u9fa5]+$";
        return str.matches(regex);
    }

    // 简单的 JSON 解析方法（可以根据实际需求进行优化）
    private static String extractJsonValue(String json, String key) {
        int startIndex = json.indexOf("\"" + key + "\":\"") + key.length() + 4;
        int endIndex = json.indexOf("\"", startIndex);
        return json.substring(startIndex, endIndex);
    }


    private static String convertToPinyin(String chinese) {
        StringBuilder pinyin = new StringBuilder();
        for (char c : chinese.toCharArray()) {
            String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c);
            if (pinyinArray != null && pinyinArray.length > 0) {
                pinyin.append(pinyinArray[0]); // 取第一个拼音
            } else {
                pinyin.append(c); // 非中文字符直接保留
            }
        }
        return pinyin.toString();
    }

    public static void main(String[] args)throws Exception {
//       GaoDeMapUtil gaoDeMapUtil=new GaoDeMapUtil();
//        String address = gaoDeMapUtil.getAddressByIP("119.123.187.146");
//        System.out.println("address:" + address);
        // 获取中国所有城市
        List<String> cities = getChineseCities();
        if (cities != null) {
            // 按字母顺序排序
            sortCitiesAlphabetically(cities);
            // 打印排序后的城市
            System.out.println("按字母顺序排序的中国城市:");
            for (String city : cities) {
                System.out.println(city);
            }
        }
    }

}

